package org.black.phoneUtility.sms.reply.app.service;

import java.util.Calendar;

import org.black.phoneUtility.database.sqlite.PhoneUtilitySQLiteOpenHelper;
import org.black.phoneUtility.sms.reply.provider.SmsReplyContract;
import org.black.phoneUtility.util.AlarmManagerUtility;

import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;

public class SmsReplyScheduleNotifyNotificationInentService extends
		IntentService {
	public static final String ARGUMENTS_SMS_REPLY_ID = "arguments_sms_reply_id";
	public static final String ARGUMENTS_ACTION_TYPE = "arguments_action_type";
	public static final String ARGUMENTS_NOTIFICATION_HAS_BEEN_SHOWN_ON_STATUS_BAR = "arguments_notification_has_been_show_on_status_bar";

	public static final int ACTION_TYPE_RECHECK = 129;
	public static final int ACTION_TYPE_SCHEDULE_SPECIFIC_SMS_REPLY = 130;

	private static final String LOG_TAG = SmsReplyScheduleNotifyNotificationInentService.class
			.getName();

	private PhoneUtilitySQLiteOpenHelper phoneUtilitySQLiteOpenHelper = null;

	public SmsReplyScheduleNotifyNotificationInentService() {
		super(SmsReplyScheduleNotifyNotificationInentService.class.getName());
	}

	@Override
	public void onCreate() {
		super.onCreate();
		this.phoneUtilitySQLiteOpenHelper = new PhoneUtilitySQLiteOpenHelper(
				this);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		this.phoneUtilitySQLiteOpenHelper.close();
		this.phoneUtilitySQLiteOpenHelper = null;
	}

	@Override
	protected void onHandleIntent(Intent intent) {
		int actionType = intent.getIntExtra(ARGUMENTS_ACTION_TYPE, 0);
		if (actionType != 0) {
			if (actionType == ACTION_TYPE_SCHEDULE_SPECIFIC_SMS_REPLY) {
				long smsReplyId = intent.getLongExtra(ARGUMENTS_SMS_REPLY_ID,
						0l);
				Cursor cursor = null;
				try {
					cursor = this.getContentResolver().query(
							SmsReplyContract.SmsReplies.CONTENT_URI, null,
							SmsReplyContract.SmsReplies._ID + " = ?",
							new String[] { String.valueOf(smsReplyId) }, null,
							null);
					if (cursor.moveToFirst() == true) {
						do {
							this.checkAndScheduleUpdateNotify(cursor);
						} while (cursor.moveToNext() == true);
					} else {
						Log.d(LOG_TAG, "No activated Sms Reply!");
					}
				} catch (Throwable throwable) {
					Log.e(LOG_TAG, "Something Wrong when querying SmsReply!",
							throwable);
				} finally {
					if (cursor != null) {
						try {
							cursor.close();
						} catch (Throwable th) {
							Log.e(LOG_TAG,
									"Fail to close cursor for querying SmsReply",
									th);
						}
					}
				}
			} else {
				Cursor cursor = null;
				try {
					cursor = this.getContentResolver().query(
							SmsReplyContract.SmsReplies.CONTENT_URI, null,
							SmsReplyContract.SmsReplies.IS_ACTIVATED + " = ?",
							new String[] { String.valueOf(1) }, null, null);
					if (cursor.moveToFirst() == true) {
						do {
							this.checkAndScheduleUpdateNotify(cursor);
						} while (cursor.moveToNext() == true);
					} else {
						Intent updateNotificationServiceIntent = new Intent(
								this, SmsReplyNotificationIntentService.class);
						Bundle arguments = new Bundle();
						arguments
								.putInt(SmsReplyNotificationIntentService.ARGUMENTS_ACTION_TYPE,
										SmsReplyNotificationIntentService.ACTION_TYPE_SMS_REPLY_RECHECK);
						updateNotificationServiceIntent.putExtras(arguments);
						startService(updateNotificationServiceIntent);
						Log.d(LOG_TAG, "No activated Sms Reply!");
					}
				} catch (Throwable throwable) {
					Log.e(LOG_TAG, "Something Wrong when querying SmsReply!",
							throwable);
				} finally {
					if (cursor != null) {
						try {
							cursor.close();
						} catch (Throwable th) {
							Log.e(LOG_TAG,
									"Fail to close cursor for querying SmsReply",
									th);
						}
					}
				}
			}
		} else {
			Log.e(LOG_TAG, "Actioin Type is 0!");
		}
	}

	private void checkAndScheduleUpdateNotify(Cursor cursor) {
		long currentTimeMillis = System.currentTimeMillis();
		AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

		int replyDateTimeModeType = cursor
				.getInt(cursor
						.getColumnIndex(SmsReplyContract.SmsReplies.REPLY_DATE_TIME_TYPE));
		long smsReplyId = cursor.getLong(cursor
				.getColumnIndex(SmsReplyContract.SmsReplies._ID));
		boolean isActivated = cursor.getInt(cursor
				.getColumnIndex(SmsReplyContract.SmsReplies.IS_ACTIVATED)) == 1 ? true
				: false;
		Intent intent = new Intent();
		intent.putExtra(
				SmsReplyScheduleUpdateSmsReplyService.ARGUMENTS_SMS_REPLY_ID,
				smsReplyId);
		intent.putExtra(
				SmsReplyScheduleUpdateSmsReplyService.ARGUMENTS_SMS_REPLY_ID,
				smsReplyId);
		intent.putExtra(
				SmsReplyNotificationIntentService.ARGUMENTS_ACTION_TYPE,
				SmsReplyNotificationIntentService.ACTION_TYPE_SMS_REPLY_SINGLE);
		Long triggerAtMillis = null;
		if (replyDateTimeModeType == SmsReplyContract.SmsReplies.REPLY_DATE_TIME_MODE_ALWAYS_TYPE) {
			this.sendSmsReplyNotificationIntentServiceImmediate(smsReplyId,
					true);
		} else if (replyDateTimeModeType == SmsReplyContract.SmsReplies.REPLY_DATE_TIME_MODE_EXPIRED_AFTER_TYPE) {
			if (isActivated == false) {
				this.sendSmsReplyNotificationIntentServiceImmediate(smsReplyId,
						true);
			} else {
				long activationDateTimeInMillis = cursor
						.getLong(cursor
								.getColumnIndex(SmsReplyContract.SmsReplies.ACTIVATION_DATE_TIME));
				long expiredAfter = activationDateTimeInMillis
						+ cursor.getLong(cursor
								.getColumnIndex(SmsReplyContract.SmsReplies.EXPIRATED_AFTER_MILLISECONDS));
				if (currentTimeMillis < activationDateTimeInMillis) {
					triggerAtMillis = activationDateTimeInMillis;
					intent.setClass(this,
							SmsReplyNotificationIntentService.class);
					intent.addCategory(String.valueOf(smsReplyId) + isActivated
							+ currentTimeMillis + activationDateTimeInMillis);
				} else if (currentTimeMillis < expiredAfter) {
					this.sendSmsReplyNotificationIntentServiceImmediate(
							smsReplyId, true);
					triggerAtMillis = expiredAfter;
					intent.setClass(this,
							SmsReplyScheduleUpdateSmsReplyService.class);
					intent.addCategory(String.valueOf(smsReplyId) + isActivated
							+ currentTimeMillis + expiredAfter);
				} else {
					triggerAtMillis = currentTimeMillis;
					intent.setClass(this,
							SmsReplyScheduleUpdateSmsReplyService.class);
					intent.addCategory(String.valueOf(smsReplyId) + isActivated
							+ currentTimeMillis + currentTimeMillis);
				}
			}
		} else if (replyDateTimeModeType == SmsReplyContract.SmsReplies.REPLY_DATE_TIME_MODE_PERIOD_TYPE) {
			long periodStartDateTimeInMillis = cursor
					.getLong(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.PERIOD_START_DATE_TIME));
			long periodEndDateTimeInMillis = cursor
					.getLong(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.PERIOD_END_DATE_TIME));
			if (isActivated == false) {
				this.sendSmsReplyNotificationIntentServiceImmediate(smsReplyId,
						true);
			} else {
				if (currentTimeMillis < periodStartDateTimeInMillis) {
					triggerAtMillis = periodStartDateTimeInMillis;
					intent.setClass(this,
							SmsReplyNotificationIntentService.class);
					intent.addCategory(String.valueOf(smsReplyId) + isActivated
							+ currentTimeMillis + periodStartDateTimeInMillis);
				} else if (currentTimeMillis <= periodEndDateTimeInMillis) {
					this.sendSmsReplyNotificationIntentServiceImmediate(
							smsReplyId, true);
					triggerAtMillis = periodEndDateTimeInMillis;
					intent.setClass(this,
							SmsReplyScheduleUpdateSmsReplyService.class);
					intent.addCategory(String.valueOf(smsReplyId) + isActivated
							+ currentTimeMillis + periodEndDateTimeInMillis);
				} else {
					triggerAtMillis = currentTimeMillis;
					intent.setClass(this,
							SmsReplyScheduleUpdateSmsReplyService.class);
					intent.addCategory(String.valueOf(smsReplyId) + isActivated
							+ currentTimeMillis + currentTimeMillis);
				}
			}
		} else if (replyDateTimeModeType == SmsReplyContract.SmsReplies.REPLY_DATE_TIME_MODE_REPEAT_TYPE) {
			boolean isSundayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_SUNDAY_ENABLE)) == 1 ? true
					: false;
			boolean isMondayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_MONDAY_ENABLE)) == 1 ? true
					: false;
			boolean isTuesdayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_TUESDAY_ENABLE)) == 1 ? true
					: false;
			boolean isWednesdayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_WEDNESDAY_ENABLE)) == 1 ? true
					: false;
			boolean isThursdayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_TUESDAY_ENABLE)) == 1 ? true
					: false;
			boolean isFridayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_FRIDAY_ENABLE)) == 1 ? true
					: false;
			boolean isSaturdayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_SATURDAY_ENABLE)) == 1 ? true
					: false;
			if (isActivated == false) {
				this.sendSmsReplyNotificationIntentServiceImmediate(smsReplyId,
						true);
			} else {
				if (isSundayEnable == false && isMondayEnable == false
						&& isTuesdayEnable == false
						&& isWednesdayEnable == false
						&& isThursdayEnable == false && isFridayEnable == false
						&& isSaturdayEnable == false) {
					long repeatStartTime = cursor
							.getLong(cursor
									.getColumnIndex(SmsReplyContract.SmsReplies.REPEAT_START_TIME));
					long repeatEndTime = cursor
							.getLong(cursor
									.getColumnIndex(SmsReplyContract.SmsReplies.REPEAT_END_TIME));
					if (currentTimeMillis < repeatStartTime) {
						triggerAtMillis = repeatStartTime;
						intent.setClass(this,
								SmsReplyNotificationIntentService.class);
						intent.addCategory(String.valueOf(smsReplyId)
								+ isActivated + currentTimeMillis
								+ repeatStartTime);
					} else if (currentTimeMillis <= repeatEndTime) {
						this.sendSmsReplyNotificationIntentServiceImmediate(
								smsReplyId, true);
						triggerAtMillis = repeatEndTime;
						intent.setClass(this,
								SmsReplyScheduleUpdateSmsReplyService.class);
						intent.addCategory(String.valueOf(smsReplyId)
								+ isActivated + currentTimeMillis
								+ repeatEndTime);
					} else {
						triggerAtMillis = currentTimeMillis;
						intent.setClass(this,
								SmsReplyScheduleUpdateSmsReplyService.class);
						intent.addCategory(String.valueOf(smsReplyId)
								+ isActivated + currentTimeMillis
								+ currentTimeMillis);
					}
				} else {
					Calendar currentCalendar = Calendar.getInstance();

					int currentHour = currentCalendar.get(Calendar.HOUR_OF_DAY);
					int currentMinute = currentCalendar.get(Calendar.MINUTE);

					Calendar startCalendar = Calendar.getInstance();
					startCalendar
							.setTimeInMillis(cursor.getLong(cursor
									.getColumnIndex(SmsReplyContract.SmsReplies.REPEAT_START_TIME)));
					Calendar endCalendar = Calendar.getInstance();
					endCalendar
							.setTimeInMillis(cursor.getLong(cursor
									.getColumnIndex(SmsReplyContract.SmsReplies.REPEAT_END_TIME)));

					int startHour = startCalendar.get(Calendar.HOUR_OF_DAY);
					int startMinute = startCalendar.get(Calendar.MINUTE);

					int endHour = endCalendar.get(Calendar.HOUR_OF_DAY);
					int endMinute = endCalendar.get(Calendar.MINUTE);
					boolean inReplyDateTimePreiod = false;
					if (startHour * 60 + startMinute >= endHour * 60
							+ endMinute) {
						endHour += 24;

					}
					int currentTimeInMinutes = currentHour * 60 + currentMinute;
					int startTimeInMinutes = startHour * 60 + startMinute;
					int endTimeInMinutes = endHour * 60 + endMinute;
					if (currentTimeInMinutes >= startTimeInMinutes
							&& currentTimeInMinutes < endTimeInMinutes) {
						inReplyDateTimePreiod = true;
					}

					int dayOfWeek = currentCalendar.get(Calendar.DAY_OF_WEEK);
					Integer nextDayOfWeek = dayOfWeek;
					boolean inDayOfWeek = false;
					if (dayOfWeek == Calendar.SUNDAY) {
						if (isSundayEnable == true) {
							inDayOfWeek = true;
						}
					} else if (dayOfWeek == Calendar.MONDAY) {
						if (isMondayEnable == true) {
							inDayOfWeek = true;
						}
					} else if (dayOfWeek == Calendar.TUESDAY) {
						if (isTuesdayEnable == true) {
							inDayOfWeek = true;
						}
					} else if (dayOfWeek == Calendar.WEDNESDAY) {
						if (isWednesdayEnable == true) {
							inDayOfWeek = true;
						}
					} else if (dayOfWeek == Calendar.THURSDAY) {
						if (isThursdayEnable == true) {
							inDayOfWeek = true;
						}
					} else if (dayOfWeek == Calendar.FRIDAY) {
						if (isFridayEnable == true) {
							inDayOfWeek = true;
						}
					} else if (dayOfWeek == Calendar.SATURDAY) {
						if (isSaturdayEnable == true) {
							inDayOfWeek = true;
						}
					} else {
						// TODO: something wrong
					}

					if (inDayOfWeek == true && inReplyDateTimePreiod == true) {
						this.sendSmsReplyNotificationIntentServiceImmediate(
								smsReplyId, true);
						Calendar targetCalendar = Calendar.getInstance();
						targetCalendar.set(Calendar.SECOND, 0);
						targetCalendar.set(Calendar.MILLISECOND, 0);
						targetCalendar.set(Calendar.HOUR_OF_DAY, endHour);
						targetCalendar.set(Calendar.MINUTE, endMinute);

						triggerAtMillis = targetCalendar.getTimeInMillis();

						intent.setClass(this,
								SmsReplyNotificationIntentService.class);
						intent.addCategory(String.valueOf(smsReplyId)
								+ isActivated + currentTimeMillis
								+ triggerAtMillis);
					} else if (inDayOfWeek == true
							&& currentHour * 60 + currentMinute < startHour
									* 60 + startMinute) {
						Calendar targetCalendar = Calendar.getInstance();
						targetCalendar.set(Calendar.MILLISECOND, 0);
						targetCalendar.set(Calendar.SECOND, 0);
						targetCalendar.set(Calendar.MINUTE, startMinute);
						targetCalendar.set(Calendar.HOUR_OF_DAY, startHour);
						triggerAtMillis = targetCalendar.getTimeInMillis();
						intent.setClass(this,
								SmsReplyNotificationIntentService.class);
						intent.addCategory(String.valueOf(smsReplyId)
								+ isActivated + currentTimeMillis
								+ triggerAtMillis);
					} else {
						boolean enableDaysOfWeek[] = new boolean[] {
								isSundayEnable, isMondayEnable,
								isTuesdayEnable, isWednesdayEnable,
								isThursdayEnable, isFridayEnable,
								isSaturdayEnable };
						int length = dayOfWeek + enableDaysOfWeek.length;
						for (int i = dayOfWeek; i < length; i++) {
							// TODO: saturday is 7
							int index = i % 7;
							if (enableDaysOfWeek[index] == true) {
								nextDayOfWeek = index + 1;
								break;
							}
						}
						int dayOffset = nextDayOfWeek - dayOfWeek;
						if (dayOffset <= 0) {
							dayOffset += 7;
						}
						Calendar targetCalendar = Calendar.getInstance();
						targetCalendar.set(Calendar.MILLISECOND, 0);
						targetCalendar.set(Calendar.SECOND, 0);
						targetCalendar.set(Calendar.MINUTE, startMinute);
						targetCalendar.set(Calendar.HOUR_OF_DAY, startHour);
						targetCalendar.add(Calendar.DAY_OF_YEAR, dayOffset);
						triggerAtMillis = targetCalendar.getTimeInMillis();

						triggerAtMillis = targetCalendar.getTimeInMillis();
						intent.setClass(this,
								SmsReplyNotificationIntentService.class);
						intent.addCategory(String.valueOf(smsReplyId)
								+ isActivated + currentTimeMillis
								+ triggerAtMillis);
					}

					Log.d(LOG_TAG, "Repeat in some day!");
				}
			}
		} else {
			Log.e(LOG_TAG,
					"Reply Date Time Type does not match. replyDateTimeModeType: "
							+ replyDateTimeModeType);
		}
		if (triggerAtMillis != null) {
			PendingIntent pendingIntent = PendingIntent.getService(this, 1,
					intent, PendingIntent.FLAG_CANCEL_CURRENT);
			AlarmManagerUtility.setAlarm(alarmManager, AlarmManager.RTC,
					triggerAtMillis, pendingIntent);
		}
	}

	private void sendSmsReplyNotificationIntentServiceImmediate(
			long smsReplyId, boolean shouldNotCallback) {
		Intent updateNotificationServiceIntent = new Intent(this,
				SmsReplyNotificationIntentService.class);
		Bundle arguments = new Bundle();
		arguments.putInt(
				SmsReplyNotificationIntentService.ARGUMENTS_ACTION_TYPE,
				SmsReplyNotificationIntentService.ACTION_TYPE_SMS_REPLY_SINGLE);
		arguments.putLong(
				SmsReplyNotificationIntentService.ARGUMENTS_SMS_REPLY_ID,
				smsReplyId);
		arguments
				.putBoolean(
						SmsReplyNotificationIntentService.ARGUMENTS_SHOULD_NOT_CALL_BACK_TO_SCHEDULE_NOTIFY_NOTIFICATION_INTENT_SERVICE,
						shouldNotCallback);
		updateNotificationServiceIntent.putExtras(arguments);
		startService(updateNotificationServiceIntent);
		Log.d(LOG_TAG, "Start SmsReplyNotificationIntentService!");

	}
}
